/*
 * Copyright 2007-2009 Perttu "celeron55" Ahola <celeron55@gmail.com>
 *
 * This file is part of jukuMagic.
 *
 * jukuMagic is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jukuMagic is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jukuMagic.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "circuit.h"
#include "commonfunctions.h"
#include <stdlib.h>
#include <fstream>

Circuit::Circuit()
{
	ClearAll();
}

void Circuit::ClearAll()
{
	maxfootnum = 0;
	connectionsfinalized = false;
	parts.clear();
	wireparts.clear();
	connections.clear();
}

int Circuit::MaxFootNum()
{
	return maxfootnum;
}

void Circuit::AddPart(Part part)
{
	cout<<"Adding part: name="<<part.Name()<<endl;
	parts.push_back(part);
	int i = part.GetFootprint()->MaxFootNum();
	if(i>maxfootnum) maxfootnum = i;
}

bool Circuit::Add1x1Part(string sname, int footnum, string footname)
{
	Part part;
	part.SetName(sname);
	Footprint fp;
	fp.Allocate(1,1);
	fp.AddFoot(0, 0, footnum, footname);
	part.SetFootprint(fp);
	AddPart(part);
	return true;
}

bool Circuit::AddRowPart(string sname, vector<int> footnums, vector<string> footnames)
{
	if(footnums.size() != footnames.size()){
		cout<<"Circuit::AddRowPart(): ERROR: different count of footnums and footnames"<<endl;
		return false;
	}
	if(footnums.size() == 0){
		cout<<"Circuit::AddRowPart(): ERROR: zero feet"<<endl;
		return false;
	}
	Part part;
	part.SetName(sname);
	Footprint fp;
	fp.Allocate(1, footnums.size());
	for(unsigned int i=0; i<footnums.size(); i++){
		fp.AddFoot(0, i, footnums[i], footnames[i]);
	}
	part.SetFootprint(fp);
	AddPart(part);
	return true;
}

//width in mil
bool Circuit::AddDILPart(string sname, unsigned int milwidth,
		vector<int> footnums, vector<string> footnames)
{
	if(footnums.size() != footnames.size()){
		cout<<"Circuit::AddDILPart(): ERROR: different count of footnums and footnames"<<endl;
		return false;
	}
	if(footnums.size() == 0){
		cout<<"Circuit::AddDILPart(): ERROR: zero feet"<<endl;
		return false;
	}
	if(footnums.size() % 2 != 0){
		cout<<"Circuit::AddDILPart(): ERROR: foot count must be even"<<endl;
		return false;
	}
	if(milwidth<=150){
		cout<<"Circuit::AddDILPart(): ERROR: milwidth has to be > 150"<<endl;
		return false;
	}
	Part part;
	part.SetName(sname);
	Footprint fp;
	unsigned int footcount = footnums.size();
	cout<<"Adding DIL "<<footcount<<" "<<milwidth<<endl;
	unsigned int length = footcount / 2;
	unsigned int width = (milwidth + 50) / 100 + 1;
	fp.Allocate(width, length);
	for(unsigned int y=0; y<length; y++){
		fp.AddFoot(0, y, footnums[y], footnames[y]);
	}
	for(unsigned int y=0; y<length; y++){
		fp.AddFoot(width-1, length-1-y, footnums[length+y], footnames[length+y]);
	}
	for(unsigned int y=0; y<length; y++){
		for(unsigned int x=1; x<width-1; x++){
			cout<<"adding block to ("<<x<<","<<y<<")"<<endl;
			fp.AddComponentBlock(x, y);
		}
	}
	part.SetFootprint(fp);
	AddPart(part);
	return true;
}

//width in blocks
bool Circuit::AddFixedLength2LeggedPart(string sname, int length,
		int footnum1, int footnum2, string footname1, string footname2)
{
	cout<<"Adding fixed-length 2-legged part, length="<<length
			<<", footnum1="<<footnum1<<", footnum2="<<footnum2<<endl;
	Part part;
	part.SetName(sname);
	Footprint fp;
	unsigned int height = length + 1;
	fp.Allocate(1, height);
	fp.AddFoot(0, 0, footnum1, footname1);
	fp.AddFoot(0, length, footnum2, footname2);
	//blokataan jalkojen väli
	for(unsigned int i=1; i<height-1; i++){
		fp.AddComponentBlock(0, i);
	}
	part.SetFootprint(fp);
	AddPart(part);
	return true;
}

bool Circuit::AddCustomFootprintPart(string sname, string footprint,
		vector<int> footnums, vector<string> footnames)
{
	if(footnums.size() != footnames.size()){
		cout<<"Circuit::AddDILPart(): ERROR: different count of footnums and footnames"<<endl;
		return false;
	}
	if(footnums.size() == 0){
		cout<<"Circuit::AddDILPart(): ERROR: zero feet"<<endl;
		return false;
	}
	Part part;
	part.SetName(sname);
	Footprint fp;
	int footcount = footnums.size();
	cout<<"Adding Custom part, footcount="<<footcount;
	int feet_added = 0;

	//lasketaan koko
	strfnd f(footprint);
	unsigned int y;
	unsigned int width = 0;
	for(y=0; !f.inend(); y++){
		string row = f.next("\n");
		if((row.size()+1)/2 > width) width = (row.size()+1)/2;
	}
	unsigned int height = y;

	cout<<", size="<<width<<"x"<<height<<endl;

	fp.Allocate(width, height);

	//lisätään blokit ja jalat
	f.moveto(0);
	for(unsigned int y=0; !f.inend(); y++){
		string row = f.next("\n");
		unsigned int x = 0;
		for(unsigned int i=0; i<row.size(); i++){
			cout<<"i="<<i<<": ";
			cout<<"x="<<x<<": ";
			if(row[i]=='.'){
				//ei mitään
				i++;
				if(i<row.size() && row[i] != ' '){
					cout<<"ERROR: row \""<<row<<"\": char number "<<i
							<<" should be space"<<endl;
				}
			}
			else if(row[i]=='X'){
				//kalikka peittää tämän kohdan
				cout<<"X"<<endl;
				fp.AddComponentBlock(x, y);
				i++;
				if(i<row.size() && row[i] != ' '){
					cout<<"ERROR: row \""<<row<<"\": char number "<<i
							<<": should be space"<<endl;
				}
			}
			else{
				//muuten tässä pitäisi olla numero, eli jalka
				int num1 = (row[i] - '0');
				cout<<"num1="<<num1<<endl;
				if(num1<0 || num1>9){
					cout<<"ERROR: row \""<<row<<"\": char number "<<i
							<<": should be number"<<endl;
					return false;
				}
				int num = num1;
				i++;
				if(i<row.size()){
					if(row[i] != ' '){
						int num2 = (row[i] - '0');
						cout<<"num2="<<num2<<endl;
						if(num2<0 || num2>9){
							cout<<"ERROR: row \""<<row<<"\": char number "<<i
									<<": should be space or number"<<endl;
							return false;
						}
						num += num2*10;
					}
				}
				num = num - 1;
				if(num>=footcount){
					cout<<"ERROR: num>=footcount"<<endl;
					return false;
				}
				cout<<"adding foot x="<<x<<" y="<<y<<endl;
				fp.AddFoot(x, y, footnums[num], footnames[num]);
				feet_added++;
			}
			x++;
		}
	}
	if(feet_added != footcount){
		cout<<"ERROR: feet_added != footcount"<<endl;
		return false;
	}
	part.SetFootprint(fp);
	cout<<"adding part"<<endl;
	AddPart(part);
	cout<<"added"<<endl;
	return true;
}

void Circuit::AddWirePart(WirePart wpart)
{
	cout<<"Adding wirepart: name="<<wpart.Name()<<" length="<<wpart.Length()
			<<" num1="<<wpart.FootNum1()<<" num2="<<wpart.FootNum2()<<endl;
	wireparts.push_back(wpart);
	int i = wpart.MaxFootNum();
	if(i>maxfootnum) maxfootnum = i;
}

void Circuit::AddWirePart(string sname, int maxlength,
		int footnum1, int footnum2, string foot1name, string foot2name)
{
	WirePart wpart;
	wpart.SetName(sname);
	wpart.SetLength(maxlength);
	wpart.SetFootNums(footnum1, footnum2);
	wpart.SetFootNames(foot1name, foot2name);
	AddWirePart(wpart);
}

void Circuit::AddConnection(Connection con)
{
	cout<<"Adding connection: "<<con.from<<" -> "<<con.to<<endl;
	connections.push_back(con);
	connectionsfinalized = false;
}

bool Circuit::AddPartFromKytString(string sname, string stype, string snumbers)
{
	//cout<<"type: '"<<stype<<"' numbers: '"<<snumbers<<"'"<<endl;
	strfnd ft(stype);
	string type0 = ft.next(" ");
	if(type0=="wirepart"){
		string slength = trim(ft.next(" "));
		int maxlength;
		if(slength!="") maxlength = atoi(slength.c_str());
		else            maxlength = 10;

		strfnd f(snumbers);
		string sn1 = f.next(" ");
		if(f.inend()) return false;
		string sn2 = f.next(" ");
		if(!f.inend()) return false;

		f.start(sn1);
		int f1 = atoi(f.next("=").c_str());
		string f1n = f.next(" ");
		f.start(sn2);
		int f2 = atoi(f.next("=").c_str());
		string f2n = f.next(" ");

		AddWirePart(sname, maxlength, f1, f2, f1n, f2n);
	}
	else if(type0=="point"){
		strfnd fn(snumbers);
		if(fn.inend()) return false;
		string feettring = fn.next(" ");
		if(!fn.inend()) return false;
		
		strfnd f(trim(feettring));
		string ns = f.next("=");
		if(ns == "") return false;

		if(!Add1x1Part(sname, atoi(ns.c_str()), f.next(""))){
			cout<<"error adding 1x1"<<endl;
			return false;
		}
	}
	else if(type0=="row"){
		vector<int> footnums;
		vector<string> footnames;
		unsigned int footcount = atoi(ft.next(" ").c_str());
		strfnd fn(snumbers);
		for(unsigned int i=0; i<footcount; i++){
			if(fn.inend()) return false;

			strfnd f(trim(fn.next(" ")));
			string ns = f.next("=");
			if(ns == "") return false;

			footnums.push_back(atoi(ns.c_str()));
			footnames.push_back(f.next(""));
		}
		if(!fn.inend()) return false;

		if(!AddRowPart(sname, footnums, footnames)){
			cout<<"error adding rowp"<<endl;
			return false;
		}
	}
	else if(type0=="DIP"){
		vector<int> footnums;
		vector<string> footnames;
		unsigned int rowspacing = atoi(ft.next(" ").c_str());
		unsigned int rowlength = atoi(ft.next(" ").c_str());
		cout<<"Adding DIP-part sized "<<rowspacing<<"x"<<rowlength<<endl;
		strfnd fn(snumbers);
		for(unsigned int y=0; y<rowlength; y++){
			strfnd f(trim(fn.next(" ")));
			string ns = f.next("=");
			if(ns == "") return false;
			footnums.push_back(atoi(ns.c_str()));
			footnames.push_back(f.next(""));
		}
		for(unsigned int y=0; y<rowlength; y++){
			strfnd f(trim(fn.next(" ")));
			string ns = f.next("=");
			if(ns == "") return false;
			footnums.push_back(atoi(ns.c_str()));
			footnames.push_back(f.next(""));
		}
		if(!fn.inend()) return false;
		if(!AddDILPart(sname, (rowspacing-1)*100, footnums, footnames)){
			cout<<"error adding dil"<<endl;
			return false;
		}
	}
	else{
		cout<<"Unknown type: "<<stype<<endl;
		return false;
	}
	return true;
}

//returns -1 if succeed, line number if failed
bool Circuit::LoadKytFile(string filename)
{
	ClearAll();
	bool donesomething = false;

	fstream kytfile(filename.c_str());
	if(kytfile.fail()){
		cout<<"Failed to open "<<filename.c_str()<<endl;
		return false;
	}
	int r = 0;
	while(!kytfile.eof()){
		char cline[1024];
		kytfile.getline(cline, 1024, ';');
		string line = cline;
		for(unsigned int i=0; i<line.size(); i++){
			if(line[i]=='\n') r++;
		}
		strfnd f(line);
		string linename = trim(f.next(":"));
		if(linename=="PART"){
			string name = trim(f.next(","));
			string type = trim(f.next(","));
			string numbers = trim(f.next(","));
			if(!AddPartFromKytString(name, type, numbers)){
				cout<<"Circuit::LoadKytFile(): Error on row "<<r<<endl;
				return false;
			}
			else donesomething = true;
		}
		else if(linename=="CON"){
			int c1 = atoi(trim(f.next(",")).c_str());
			int c2 = atoi(trim(f.next(",")).c_str());
			Connection con(c1, c2);
			AddConnection(con);
			donesomething = true;
		}
		else{
			cout<<"Circuit::LoadKytFile(): Bad linename on row "<<r<<endl;
		}
	}
	kytfile.close();
	return donesomething;
}

unsigned int GetFootprintFootCount(string footprint)
{
	strfnd f(footprint);
	string first = f.next(" ");
	if(
			first == "R025" ||
			first == "R025_FIXED" ||
			first == "DIODE" ||
			first == "DIODE_FIXED" ||
			first == "AXIAL_LAY" ||
			first == "ROUND2" ||
			first == "ROUND2P" ||
			first == "LED"
	){
		return 2;
	}
	if(first == "CONNECTOR"){
		return atoi(f.next(" ").c_str()) * atoi(f.next("").c_str());
	}
	if(first == "TO92"){
		return 3;
	}
	if(first == "TO220"){
		return 3;
	}
	if(first == "DIL"){
		return atoi(f.next(" ").c_str());
	}
	if(first.substr(0,3)=="DIP"){
		return atoi(first.substr(3).c_str());
	}
	if(first.substr(0,3)=="ACY"){
		return 2;
	}
	if(first.substr(0,3)=="RCY"){
		return 2;
	}
	if(first.substr(0,3)=="ALF"){
		return 2;
	}
	if(first.substr(0,6)=="JUMPER"){
		return 2;
	}
	if(first == "R_VAR_1"){
		return 3;
	}
	return 0;
}

vector<string> CreateFootNames(unsigned int footcount){
	vector<string> footnames;
	for(unsigned int i=0; i<footcount; i++){
		char s[10];
		sprintf(s, "<%i>", i+1);
		footnames.push_back(s);
	}
	return footnames;
}

bool Circuit::AddPart(PadsPart padspart)
{
	cout<<"Circuit::AddPart(): adding "<<padspart.footprint
			<<" named \""<<padspart.name<<"\""<<endl;
	strfnd fnd(padspart.footprint);
	string ffirst = fnd.next(" ");
	string fsecond = fnd.next(" ");
	string fthird = fnd.next(" ");

	if(padspart.footprint == "R025" || padspart.footprint.substr(0,3) == "ACY"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		cout<<"WirePart, footnums "<<padspart.circuitfootnums[0]<<" and "
				<<padspart.circuitfootnums[1]<<endl;
		AddWirePart(padspart.name, 10, padspart.circuitfootnums[0],
				padspart.circuitfootnums[1], "Rfoot", "Rfoot");
		return true;
	}
	if(ffirst == "R025_FIXED"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		unsigned int footdistance = atoi(trim(fsecond).c_str());
		if(footdistance==0){
			cout<<"invalid foot distance"<<endl;
			return false;
		}
		AddFixedLength2LeggedPart(padspart.name, footdistance,
						padspart.circuitfootnums[0],
		                padspart.circuitfootnums[1], "", "");
		return true;
	}

	if(ffirst == "DIODE" || ffirst.substr(0,3) == "ALF"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		cout<<"WirePart, footnums "<<padspart.circuitfootnums[0]<<" and "
				<<padspart.circuitfootnums[1]<<endl;
		AddWirePart(padspart.name, 10, padspart.circuitfootnums[0],
				padspart.circuitfootnums[1], "cathode", "anode");
		return true;
	}
	if(ffirst == "DIODE_FIXED"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		unsigned int footdistance = atoi(trim(fsecond).c_str());
		if(footdistance==0){
			cout<<"invalid foot distance"<<endl;
			return false;
		}
		AddFixedLength2LeggedPart(padspart.name, footdistance,
						padspart.circuitfootnums[0],
		                padspart.circuitfootnums[1], "cathode", "anode");
		return true;
	}

	if(ffirst == "AXIAL_LAY"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		unsigned int footdistance = atoi(trim(fsecond).c_str());
		if(footdistance==0){
			cout<<"invalid foot distance"<<endl;
			return false;
		}
		AddFixedLength2LeggedPart(padspart.name, (footdistance+50)/100,
						padspart.circuitfootnums[0],
		                padspart.circuitfootnums[1], "", "");
		return true;
	}

	if(ffirst == "ROUND2"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		unsigned int footdistance = atoi(trim(fsecond).c_str());
		if(footdistance==0){
			cout<<"invalid foot distance"<<endl;
			return false;
		}
		//int diameter = atoi(trim(fnd.next("")).c_str());
		AddFixedLength2LeggedPart(padspart.name, footdistance,
						padspart.circuitfootnums[0],
		                padspart.circuitfootnums[1], "", "");
		return true;
	}
	if(ffirst.substr(0,3) == "RCY"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		unsigned int footdistance = (atoi(trim(ffirst.substr(3)).c_str())+50)/100;
		if(footdistance==0){
			cout<<"invalid foot distance"<<endl;
			return false;
		}
		//int diameter = atoi(trim(fnd.next("")).c_str());
		AddFixedLength2LeggedPart(padspart.name, footdistance,
						padspart.circuitfootnums[0],
		                padspart.circuitfootnums[1], "", "");
		return true;
	}
	if(ffirst.substr(0,6) == "JUMPER"){
		unsigned int footcount = atoi(trim(ffirst.substr(6)).c_str());
		if(footcount==0){
			cout<<"invalid foot count"<<endl;
			return false;
		}
		vector<string> footnames = CreateFootNames(padspart.circuitfootnums.size());
		AddRowPart(padspart.name, padspart.circuitfootnums, footnames);
		return true;
	}
	if(ffirst == "ROUND2P"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		unsigned int footdistance = atoi(trim(fsecond).c_str());
		if(footdistance==0){
			cout<<"invalid foot distance"<<endl;
			return false;
		}
		//int diameter = atoi(trim(fnd.next("")).c_str());
		AddFixedLength2LeggedPart(padspart.name, footdistance,
						padspart.circuitfootnums[0],
		                padspart.circuitfootnums[1], "+", "-");
		return true;
	}
	
	if(ffirst == "LED"){
		if(padspart.circuitfootnums.size() != 2){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 2"<<endl;
			return false;
		}
		unsigned int footdistance = atoi(trim(fsecond).c_str());
		if(footdistance==0){
			cout<<"invalid foot distance"<<endl;
			return false;
		}
		//int diameter = atoi(trim(fnd.next("")).c_str());
		AddFixedLength2LeggedPart(padspart.name, footdistance,
						padspart.circuitfootnums[0],
		                padspart.circuitfootnums[1], "cathode", "anode");
		return true;
	}

	if(ffirst == "CONNECTOR"){
		unsigned int height = atoi(fsecond.c_str());
		unsigned int width = atoi(fthird.c_str());
		if(height == 1){
			unsigned int temp = width;
			width = height;
			height = temp;
		}
		cout<<"connector height="<<height<<", width="<<width<<endl;
		if(width!=1){
			cout<<"AddPart(): ERROR: connectors are supported only with a width of 1"<<endl;
			return false;
		}
		if(height*width != padspart.circuitfootnums.size()){
			cout<<"AddPart(): ERROR: invalid foot count"<<endl;
			return false;
		}
		vector<string> footnames = CreateFootNames(padspart.circuitfootnums.size());
		AddRowPart(padspart.name, padspart.circuitfootnums, footnames);
		return true;
	}

	if(padspart.footprint == "TO92"){
		if(padspart.circuitfootnums.size() != 3){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 3"<<endl;
			return false;
		}
		cout<<"Part (row), footnums "<<padspart.circuitfootnums[0]<<", "
				<<padspart.circuitfootnums[1]<<", "
				<<padspart.circuitfootnums[2]<<endl;
		vector<string> footnames;
		footnames.push_back("1");
		footnames.push_back("2");
		footnames.push_back("3");
		AddRowPart(padspart.name, padspart.circuitfootnums, footnames);
		return true;
	}

	if(padspart.footprint == "TO220"){
		if(padspart.circuitfootnums.size() != 3){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 3"<<endl;
			return false;
		}
		cout<<"Part (row), footnums "<<padspart.circuitfootnums[0]<<", "
				<<padspart.circuitfootnums[1]<<", "
				<<padspart.circuitfootnums[2]<<endl;
		vector<string> footnames;
		footnames.push_back("1");
		footnames.push_back("2");
		footnames.push_back("3");
		AddRowPart(padspart.name, padspart.circuitfootnums, footnames);
		return true;
	}

	if(ffirst == "DIL"){
		vector<string> footnames = CreateFootNames(padspart.circuitfootnums.size());
		strfnd f(padspart.footprint);
		f.next(" "); //DIL
		f.next(" "); //<footcount>
		int milwidth = atoi(trim(f.next("")).c_str());
		cout<<"Part (DIL), feet: "<<endl;
		for(unsigned int i=0; i<padspart.circuitfootnums.size(); i++){
			cout<<"on part: "<<i<<", on circuit: "<<padspart.circuitfootnums[i]<<endl;
		}
		AddDILPart(padspart.name, milwidth, padspart.circuitfootnums, footnames);
		return true;
	}

	if(ffirst.substr(0,3) == "DIP"){
		vector<string> footnames = CreateFootNames(padspart.circuitfootnums.size());
		strfnd f(padspart.footprint);
		/*f.next(" "); //DIL
		f.next(" "); //<footcount>
		int milwidth = atoi(trim(f.next("")).c_str());*/
		int milwidth = 300;
		cout<<"Part (DIL), feet: "<<endl;
		for(unsigned int i=0; i<padspart.circuitfootnums.size(); i++){
			cout<<"on part: "<<i<<", on circuit: "<<padspart.circuitfootnums[i]<<endl;
		}
		AddDILPart(padspart.name, milwidth, padspart.circuitfootnums, footnames);
		return true;
	}

	if(ffirst == "R_VAR_1"){
		if(padspart.circuitfootnums.size() != 3){
			cout<<"AddPart(): ERROR: padspart.circuitfootnums.size() != 3"<<endl;
			return false;
		}
		vector<string> footnames = CreateFootNames(padspart.circuitfootnums.size());
		cout<<"Part (R_ADJ_1), feet: "<<endl;
		for(unsigned int i=0; i<padspart.circuitfootnums.size(); i++){
			cout<<"on part: "<<i<<", on circuit: "<<padspart.circuitfootnums[i]<<endl;
		}
		AddCustomFootprintPart(padspart.name, "1 X 2\nX X X\nX X X\nX X X\nX 3 X",
				padspart.circuitfootnums, footnames);
		return true;
	}

	cout<<"AddPart(): ERROR: \""<<padspart.footprint<<"\" not supported"<<endl;

	return false;
}

enum PadsArea { PA_UNKNOWN, PA_PART, PA_NET };

bool Circuit::LoadPadsFile(string filename)
{
	ClearAll();

	fstream file(filename.c_str());
	if(file.fail()){
		cout<<"Failed to open "<<filename.c_str()<<endl;
		return false;
	}
	
	int nextfootnum = 0;
	unsigned int rownum = 0;
	char cline[1024];
	PadsArea a = PA_UNKNOWN;
	vector<PadsPart> padsparts;

	while(!file.eof()){
		file.getline(cline, 1024);
loadpads_1:
		rownum++;
		string line = cline;
		//cout<<"\""<<line<<"\""<<endl;
		if(trim(line)==""){
			a = PA_UNKNOWN;
		}
		if(trim(line) == "*END*"){
			cout<<"Circuit::LoadPadsFile(): end"<<endl;
			break;
		}
		switch(a){
		case PA_UNKNOWN: {
			if(trim(line) == "*PART*"){
				a = PA_PART;
			}
			else if(trim(line) == "*NET*"){
				a = PA_NET;
			}
			break; }
		case PA_PART: {
			strfnd f(line);
			PadsPart padspart;
			padspart.name = trim(f.next("\t"));
			padspart.footprint = trim(f.next(""));
			unsigned int footcount = GetFootprintFootCount(padspart.footprint);
			if(footcount == 0){
				cout<<"Circuit::LoadPadsFile(): ERROR: Invalid footprint \""
						<<padspart.footprint<<"\" on row "<<rownum<<endl;
				return false;
			}
			for(unsigned int i=0; i<footcount; i++){
				padspart.circuitfootnums.push_back(nextfootnum);
				nextfootnum++;
			}
			cout<<"Circuit::LoadPadsFile(): adding part named \""<<padspart.name
					<<"\" with footprint \""<<padspart.footprint<<"\""<<endl;

			padsparts.push_back(padspart);

			if(!AddPart(padspart)){
				return false;
			}

			break; }
		case PA_NET: {
			strfnd f(line);
			string first = f.next(" ");
			if(first == "*SIGNAL*"){
				//string signame = trim(f.next(""));
				if(file.eof()){
					cout<<"Circuit::LoadPadsFile(): ERROR: EOF after *SIGNAL*"<<endl;
					return false;
				}
				file.getline(cline, 1024);
loadpads_2:
				rownum++;
				string line = cline;
				//cout<<"(signal) \""<<line<<"\""<<endl;
				f.start(line.substr(1)); //skipataan ensimmäinen väli
				string sfirstfoot = f.next(" ");
				strfnd f2(sfirstfoot);
				string firstfoot_partname = f2.next(".");
				int firstfoot_partfootnum = atoi(f2.next("").c_str()) - 1;
				//etsitään osa listalta
				bool found = false;
				unsigned int i;
				for(i=0; i<padsparts.size(); i++){
					if(padsparts[i].name == firstfoot_partname){
						found = true;
						break;
					}
				}
				if(!found){
					cout<<"Circuit::LoadPadsFile(): ERROR: can't find first part \""
							<<firstfoot_partname<<"\" referred on row "<<rownum<<endl;
					return false;
				}

				int firstfoot_partnum = i;
				
				cout<<"firstfoot_partnum="<<firstfoot_partnum
						<<", firstfoot_partfootnum="<<firstfoot_partfootnum<<endl;

				int con_from = padsparts[firstfoot_partnum]
						.circuitfootnums[firstfoot_partfootnum];

				for(;;){
					string sfoot = trim(f.next(" "));
					if(sfoot==""){
						break;
					}
					//cout<<"sfoot=\""<<sfoot<<"\""<<endl;
					strfnd f3(sfoot);
					string foot_partname = f3.next(".");
					int foot_partfootnum = atoi(f3.next("").c_str()) - 1;
					bool found = false;
					unsigned int i;
					for(i=0; i<padsparts.size(); i++){
						if(padsparts[i].name == foot_partname){
							found = true;
							break;
						}
					}
					if(!found){
						cout<<"Circuit::LoadPadsFile(): ERROR: can't find part \""
								<<foot_partname<<"\" referred on row "<<rownum<<endl;
						return false;
					}
					int foot_partnum = i;

					int con_to = padsparts[foot_partnum]
							.circuitfootnums[foot_partfootnum];

					cout<<"Circuit::LoadPadsFile(): connecting from "<<con_from<<" to "
							<<con_to<<endl;

					Connection con(con_from, con_to);
					AddConnection(con);
				}

				file.getline(cline, 1024);
				if(cline[0]==' ') goto loadpads_2;
				else goto loadpads_1;
			}
			break; }
		}
	}
	file.close();
	return true;
}

//true on success
bool Circuit::LoadFile(string filename)
{
	fstream file(filename.c_str());
	if(file.fail()){
		cout<<"Circuit::LoadFile(): Failed to open "<<filename.c_str()<<endl;
		return false;
	}
	char cline[1024];
	file.getline(cline, 1024);
	string line = cline;
	file.close();
	bool b = false;
	if(trim(line) == "!PADS-POWERPCB-V3.0-MILS!"){
		b = LoadPadsFile(filename);
	}
	else{
		b = LoadKytFile(filename);
	}
	if(b){
		parts = SortPartsByFootCount(parts);
		return true;
	}
	else{
		cout<<"Circuit::LoadFile(): ERROR: Loading failed"<<endl;
		return b;
	}
}

vector<Part> & Circuit::Parts()
{
	return parts;
}

vector<WirePart> & Circuit::WireParts()
{
	return wireparts;
}

vector<Connection> & Circuit::Connections()
{
	return connections;
}

vector<Part> * Circuit::PartsP()
{
	return &parts;
}

vector<WirePart> * Circuit::WirePartsP()
{
	return &wireparts;
}

vector<Connection> * Circuit::ConnectionsP()
{
	return &connections;
}

int Circuit::FindPartNumWithFootNum(int num)
{
	for(unsigned int i=0; i<parts.size(); i++){
		if(parts[i].GetFootprint()->GetFootByNumber(num).number != -1) return i;
	}
	return -1;
}

int Circuit::FindWirePartNumWithFootNum(int num)
{
	//cout<<"Circuit::FindWirePartNumWithFootNum("<<num<<")"<<endl;
	//cout<<"We have "<<wireparts.size()<<" wireparts"<<endl;
	for(unsigned int i=0; i<wireparts.size(); i++){
		//cout<<"Part "<<i<<" is named "<<wireparts[i].Name()<<" and has footnums "<<wireparts[i].FootNum1()
				//<<" and "<<wireparts[i].FootNum2()<<endl;
		if(wireparts[i].FootNum1() == num) return i;
		if(wireparts[i].FootNum2() == num) return i;
	}
	return -1;
}

vector<int> Circuit::GetFootNumsConnectedDirectly(int num)
{
	vector<int> footnums;
	for(unsigned int i=0; i<connections.size(); i++){
		if(connections[i].from == num) footnums.push_back(connections[i].to);
		//if(connections[i].to == num) footnums.push_back(connections[i].from);
	}
	return footnums;
}

void Circuit::GetAllFootNumsConnected(int num, vector<int> *alreadysearched)
{
	//cout<<"Circuit::GetAllFootNumsConnected("<<num<<", alreadysearched.size()="<<alreadysearched.size()
			//<<")"<<endl;
	vector<int> dconnected;
	for(unsigned int i=0; i<connections.size(); i++){
		if(connections[i].from == num) dconnected.push_back(connections[i].to);
		if(connections[i].to == num) dconnected.push_back(connections[i].from);
	}
	//vector<int> dconnected = GetFootNumsConnectedDirectly(num);
	for(unsigned int i=0; i<dconnected.size(); i++){
		bool is_alreadysearched = false;
		for(unsigned int a=0; a<alreadysearched->size(); a++){
			if(dconnected[i] == (*alreadysearched)[a]){
				is_alreadysearched = true;
				break;
			}
		}
		if(!is_alreadysearched){
			alreadysearched->push_back(dconnected[i]);
			GetAllFootNumsConnected(dconnected[i], alreadysearched);
		}
	}
	//return alreadysearched;
}

//lisäilee Circuit::connections-vektoriin kaikki connectionit
//(esim. 1->2 JA 2->1)
void Circuit::FinalizeConnections()
{
	cout<<"Circuit::FinalizeConnections()"<<endl;
	//haetaan kaikki jalkanumerot
	vector<int> all_legnums;
	for(unsigned int i=0; i<connections.size(); i++){
		int num1 = connections[i].from;
		int num2 = connections[i].to;
		bool num1found = false, num2found = false;

		for(unsigned int a=0; a<all_legnums.size(); a++){
			if(all_legnums[a] == num1){
				num1found = true;
				break;
			}
		}
		if(!num1found) all_legnums.push_back(num1);

		for(unsigned int a=0; a<all_legnums.size(); a++){
			if(all_legnums[a] == num2){
				num2found = true;
				break;
			}
		}
		if(!num2found) all_legnums.push_back(num2);
	}
	vector<Connection> connections2;
	for(unsigned int i=0; i<all_legnums.size(); i++){
		int num = all_legnums[i];
		//cout<<"Circuit::FinalizeConnections Processing foot number "<<num<<endl;
		Connection c;
		c.from = num;
		vector<int> footnums;
		GetAllFootNumsConnected(num, &footnums);
		for(unsigned int a=0; a<footnums.size(); a++){
			if(footnums[a] != num){
				c.to = footnums[a];
				connections2.push_back(c);
				if(debugmessages_on) cout<<"Circuit::FinalizeConnections: Added connection "
						<<c.from<<" -> "<<c.to<<endl;
			}
		}
	}
	connections.clear();
	for(unsigned int i=0; i<connections2.size(); i++){
		connections.push_back(connections2[i]);
	}
	connectionsfinalized = true;
}

vector<int> Circuit::GetFootNumsConnected(int num)
{
	if(!connectionsfinalized) FinalizeConnections();
	return GetFootNumsConnectedDirectly(num);
}


